﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace GBPVRLibrary.UtilityLibrary.ComputerSystem
{
    public class OpticalDrive
    {
        // Constants used in DLL methods
        const uint GENERICREAD = 0x80000000;
        const uint OPENEXISTING = 3;
        const uint IOCTL_STORAGE_EJECT_MEDIA = 2967560;
        const uint IOCTL_STORAGE_LOAD_MEDIA = 2967564;
        const int INVALID_HANDLE = -1;


        // File Handle
        private static IntPtr fileHandle;
        private static uint returnedBytes;

        // Use Kernel32 via interop to access required methods

        // Get a File Handle
        [DllImport("kernel32", SetLastError = true)]
        static extern IntPtr CreateFile(string FileName, uint DesiredAccess, uint ShareMode, IntPtr Attributes, uint CreationDisposition, uint FlagsAndAttributes, IntPtr TemplateFile);

        [DllImport("kernel32", SetLastError = true)]
        static extern int CloseHandle(IntPtr DriveHandle);

        [DllImport("kernel32", SetLastError = true)]
        static extern bool DeviceIoControl(IntPtr DriveHandle, uint IoControlCode, IntPtr LpInBuffer, uint InBufferSize, IntPtr LpOutBuffer, uint OutBufferSize, ref uint LpBytesReturned, IntPtr LpOverlapped);

        public static void Eject(char DriveLetter, bool Eject)
        {
            try
            {
                // Create an handle to the drive
                fileHandle = CreateFile(String.Format(@"\\.\{0}:", DriveLetter.ToString()),
                GENERICREAD,
                0,
                IntPtr.Zero,
                OPENEXISTING,
                0,
                IntPtr.Zero);

                if ((int)fileHandle != INVALID_HANDLE)
                {
                    // Eject the disk
                    DeviceIoControl(fileHandle,
                    Eject ? IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA,
                    IntPtr.Zero, 0,
                    IntPtr.Zero, 0,
                    ref returnedBytes,
                    IntPtr.Zero);
                }
            }
            catch
            {
                throw new Exception(Marshal.GetLastWin32Error().ToString());
            }
            finally
            {
                // Close Drive Handle
                CloseHandle(fileHandle);
                fileHandle = IntPtr.Zero;
            }
        } 
    }
}
